//------------------------------------------------------------------------------
//  binaryreader.cc
//  (C) 2006 Radon Labs GmbH
//------------------------------------------------------------------------------
#include "Pch.h"
#include "binaryreader.h"

namespace GBase
{
	//------------------------------------------------------------------------------
	/**
	*/
	BinaryReader::BinaryReader() :
		enableMapping(false),
		isMapped(false),
		mapCursor(0),
		mapEnd(0)
	{
		// empty
	}

	//------------------------------------------------------------------------------
	/**
	*/
	BinaryReader::~BinaryReader()
	{
		if (this->IsOpen())
		{
			this->Close();
		}
	}

	//------------------------------------------------------------------------------
	/**
	*/
	bool
	BinaryReader::Open()
	{
		if (StreamReader::Open())
		{
			if (this->enableMapping && this->stream->CanBeMapped())
			{
				this->isMapped = true;
				this->mapCursor = (unsigned char*) this->stream->Map();
				this->mapEnd = this->mapCursor + this->stream->GetSize();
			}
			else
			{
				this->isMapped = false;
				this->mapCursor = 0;
				this->mapEnd = 0;
			}
			return true;
		}
		return false;
	}

	//------------------------------------------------------------------------------
	/**
	*/
	void
	BinaryReader::Close()
	{
		StreamReader::Close();
		this->isMapped = false;
		this->mapCursor = 0;
		this->mapEnd = 0;
	}

	//------------------------------------------------------------------------------
	/**
	*/
	char
	BinaryReader::ReadChar()
	{
		if (this->isMapped)
		{
			checkSlow(this->mapCursor < this->mapEnd);
			return *this->mapCursor++;
		}
		else
		{
			char c;
			this->stream->Read(&c, sizeof(c));
			return c;
		}
	}

	//------------------------------------------------------------------------------
	/**
	*/
	unsigned char
	BinaryReader::ReadUChar()
	{
		if (this->isMapped)
		{
			checkSlow(this->mapCursor < this->mapEnd);
			return *this->mapCursor++;
		}
		else
		{
			unsigned char c;
			this->stream->Read(&c, sizeof(c));
			return c;
		}
	}

	//------------------------------------------------------------------------------
	/**
	*/
	short
	BinaryReader::ReadShort()
	{
		short val;
		if (this->isMapped)
		{
			// note: the memory copy is necessary to circumvent alignment problem on some CPUs
			checkSlow((this->mapCursor + sizeof(short)) <= this->mapEnd);        
			//Memory::Copy(this->mapCursor, &val, sizeof(val));
			memcpy(&val, this->mapCursor, sizeof(val));
			this->mapCursor += sizeof(val);
		}
		else
		{
			this->stream->Read(&val, sizeof(val));
		}
		return val;
	}

	//------------------------------------------------------------------------------
	/**
	*/ 
	unsigned short
	BinaryReader::ReadUShort()
	{
		unsigned short val;
		if (this->isMapped)
		{
			// note: the memory copy is necessary to circumvent alignment problem on some CPUs
			checkSlow((this->mapCursor + sizeof(unsigned short)) <= this->mapEnd);
			//Memory::Copy(this->mapCursor, &val, sizeof(val));
			memcpy(&val, this->mapCursor, sizeof(val));
			this->mapCursor += sizeof(val);
		}
		else
		{
			this->stream->Read(&val, sizeof(val));
		}
		return val;
	}

	//------------------------------------------------------------------------------
	/**
	*/
	int
	BinaryReader::ReadInt()
	{
		int val;
		if (this->isMapped)
		{
			// note: the memory copy is necessary to circumvent alignment problem on some CPUs
			checkSlow((this->mapCursor + sizeof(int)) <= this->mapEnd);
			//Memory::Copy(this->mapCursor, &val, sizeof(val));
			memcpy(&val, this->mapCursor, sizeof(val));
			this->mapCursor += sizeof(val);
		}
		else
		{
			this->stream->Read(&val, sizeof(val));
		}
		//this->byteOrder.Convert<int>(val);
		return val;
	}

	//------------------------------------------------------------------------------
	/**
	*/
	unsigned int
	BinaryReader::ReadUInt()
	{
		unsigned int val;
		if (this->isMapped)
		{
			// note: the memory copy is necessary to circumvent alignment problem on some CPUs
			checkSlow((this->mapCursor + sizeof(unsigned int)) <= this->mapEnd);
			//Memory::Copy(this->mapCursor, &val, sizeof(val));
			memcpy(&val, this->mapCursor, sizeof(val));
			this->mapCursor += sizeof(val);
		}
		else
		{
			this->stream->Read(&val, sizeof(val));
		}
		//this->byteOrder.Convert<unsigned int>(val);
		return val;
	}

	//------------------------------------------------------------------------------
	/**
	*/
	float
	BinaryReader::ReadFloat()
	{
		float val;
		if (this->isMapped)
		{
			// note: the memory copy is necessary to circumvent alignment problem on some CPUs
			checkSlow((this->mapCursor + sizeof(float)) <= this->mapEnd);
			//Memory::Copy(this->mapCursor, &val, sizeof(val));
			memcpy(&val, this->mapCursor, sizeof(val));
			this->mapCursor += sizeof(val);
		}
		else
		{
			this->stream->Read(&val, sizeof(val));
		}
		//this->byteOrder.Convert<float>(val);
		return val;
	}

	//------------------------------------------------------------------------------
	/**
	*/
	double
	BinaryReader::ReadDouble()
	{
		double val;
		if (this->isMapped)
		{
			// note: the memory copy is necessary to circumvent alignment problem on some CPUs
			checkSlow((this->mapCursor + sizeof(double)) <= this->mapEnd);
			//Memory::Copy(this->mapCursor, &val, sizeof(val));
			memcpy(&val, this->mapCursor, sizeof(val));
			this->mapCursor += sizeof(val);
		}
		else
		{
			this->stream->Read(&val, sizeof(val));
		}
		//this->byteOrder.Convert<double>(val);
		return val;
	}

	//------------------------------------------------------------------------------
	/**
	*/
	bool
	BinaryReader::ReadBool()
	{
		bool val;
		if (this->isMapped)
		{
			// note: the memory copy is necessary to circumvent alignment problem on some CPUs
			checkSlow((this->mapCursor + sizeof(bool)) <= this->mapEnd);
			//Memory::Copy(this->mapCursor, &val, sizeof(val));
			memcpy(&val, this->mapCursor, sizeof(val));
			this->mapCursor += sizeof(val);
		}
		else
		{
			this->stream->Read(&val, sizeof(val));        
		}
		return val;
	}

	//------------------------------------------------------------------------------
	/**
	*/
	long long 
	BinaryReader::ReadLLong()
	{
		long long val;
		if (this->isMapped)
		{
			// note: the memory copy is necessary to circumvent alignment problem on some CPUs
			checkSlow((this->mapCursor + sizeof(long long)) <= this->mapEnd);
			//Memory::Copy(this->mapCursor, &val, sizeof(val));
			memcpy(&val, this->mapCursor, sizeof(val));
			this->mapCursor += sizeof(val);
		}
		else
		{
			this->stream->Read(&val, sizeof(val));        
		}
		return val;
	}

	//------------------------------------------------------------------------------
	/**
	*/
	unsigned long long 
	BinaryReader::ReadULLong()
	{
		unsigned long long val;
		if (this->isMapped)
		{
			// note: the memory copy is necessary to circumvent alignment problem on some CPUs
			checkSlow((this->mapCursor + sizeof(unsigned long long)) <= this->mapEnd);
			//Memory::Copy(this->mapCursor, &val, sizeof(val));
			memcpy(&val, this->mapCursor, sizeof(val));
			this->mapCursor += sizeof(val);
		}
		else
		{
			this->stream->Read(&val, sizeof(val));        
		}
		return val;
	}

	char* BinaryReader::ReadString1024()
	{
		unsigned short length = this->ReadUShort();
		if (length == 0)
		{
			return 0;
		}

		if (length > 1023)
		{
			length = 1023;
		}

		if (this->isMapped)
		{
			checkSlow((this->mapCursor + length) <= this->mapEnd);
			char* str = Stream::GetAString1024();
			if (length > 0)
			{
				memcpy(str, this->mapCursor, length);
				this->mapCursor += length;
				str[length] = 0;
			}
			return str;    
		}
		else
		{
			char* str = Stream::GetAString1024();
			
			if (length > 0)
			{
				//str.Reserve(length + 1);
				//char* buf = (char*) str.AsCharPtr();
				this->stream->Read((void*)str, length);
				str[length] = 0;
			}
			return str;
		}
	}

	void
	BinaryReader::ReadRawData(void* ptr, unsigned int numBytes)
	{
		checkSlow((ptr != 0) && (numBytes > 0));
		if (this->isMapped)
		{
			checkSlow((this->mapCursor + numBytes) <= this->mapEnd);
			//Memory::Copy(this->mapCursor, ptr, numBytes);
			memcpy(ptr, this->mapCursor, numBytes);
			this->mapCursor += numBytes;
		}
		else
		{
			this->stream->Read(ptr, numBytes);
		}
	}

} // namespace Core
